#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "data.h"
#include "interface.h"
#include "game.h"
#include "render_util.h"

static Color hex_color(int hex) {
    return (Color) {
        .r = (hex >> 16) & 0xFF,
        .g = (hex >> 8) & 0xFF,
        .b = hex & 0xFF
    };
}

void pacman_interface_init(GameInterface* controller) {
    memset(controller, 0, sizeof(GameInterface));
    DisplayInfo* display_info = &controller->display_info;
    memset(display_info->tiles, 255, sizeof(display_info->tiles));

    display_info->screen_width = 224;
    display_info->screen_height = 288;

    // setup colors
    display_info->colors[0]  = hex_color(0x000000); // black
    display_info->colors[1]  = hex_color(0xFF0000); // blinky color (red)
    display_info->colors[2]  = hex_color(0xDE9751); // brown color
    display_info->colors[3]  = hex_color(0xFFB8FF); // pinky color
    display_info->colors[4]  = hex_color(0x000000); // black
    display_info->colors[5]  = hex_color(0x00FFFF); // inky color (cyan)
    display_info->colors[6]  = hex_color(0x47B8FF); // another cyan?
    display_info->colors[7]  = hex_color(0xFFB851); // some kind of orange
    display_info->colors[8]  = hex_color(0x000000); // black
    display_info->colors[9]  = hex_color(0xFFFF00); // pure yellow (pacman color)
    display_info->colors[10] = hex_color(0x000000); // black
    display_info->colors[11] = hex_color(0x2121FF); // a deep blue
    display_info->colors[12] = hex_color(0x00FF00); // pure green
    display_info->colors[13] = hex_color(0x47B8AE); // turquoise
    display_info->colors[14] = hex_color(0xFFB8AE); // pink color
    display_info->colors[15] = hex_color(0xDEDEFF); // non-pure white

    // store init data
    display_info->palettes = (const Palette*) PALETTE_DATA;
    display_info->characterGraphics = CHARACTER_DATA;
    display_info->spriteGraphics = SPRITE_DATA;

    // create game
    controller->game = (Game*) malloc(sizeof(Game));
    game_init(controller->game, controller);
    game_reset(controller->game, FALSE);
    sound_init(&controller->sound);

    sound_start_dump(&controller->sound, 2, SOUND_PRELUDE, sizeof(SOUND_PRELUDE) / sizeof(*SOUND_PRELUDE));
}

void pacman_interface_destroy(GameInterface* controller) {
    game_free(controller->game);
    free(controller->game);
    controller->game = NULL;

    sound_free(&controller->sound);
}

void pacman_interface_update(GameInterface* interface) {
    DisplayUtilState render;
    display_init(&render, interface);
    
    game_tick(interface->game);
    game_draw(interface->game, &render);

    sound_update(&interface->sound);
    interface->last_inputs = interface->inputs;
}

void pacman_interface_setup_sound(GameInterface* interface, unsigned int sample_rate, SubmitAudioCallback callback, void* userdata) {
    interface->sound.audio_userdata = userdata;
    interface->sound.submit_audio = callback;
    interface->sound.sample_rate = sample_rate;
}

extern DisplayInfo* pacman_interface_get_display_info(GameInterface* interface) {
    return &interface->display_info;
}

extern void pacman_interface_set_inputs(GameInterface* interface, uint8_t input_flags) {
    interface->inputs = input_flags;
}